package me.huqiao.loganlyzer;


import com.soap.util.IPSearch;
import me.huqiao.loganlyzer.console.ShowHeadMsg;
import me.huqiao.loganlyzer.main.FileScaner;
import me.huqiao.loganlyzer.orderby.OrderBy;
import me.huqiao.loganlyzer.querylanguage.LogQueryLanguageParserStateMachine;
import me.huqiao.loganlyzer.util.NumberUtil;
import me.huqiao.loganlyzer.util.ProcessUtil;
import me.huqiao.loganlyzer.util.StringUtil;
import me.huqiao.loganlyzer.condition.Conditions;
import me.huqiao.loganlyzer.util.TomcatAccessLogValid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工具类主入口
 * @author soap09
 */
public class AnalysisUtil {
    private static Logger log = LoggerFactory.getLogger(AnalysisUtil.class);
    private FileScaner scaner;
    private String logPattern;
    private static AnalysisUtil instance = new AnalysisUtil();
    private ShowHeadMsg headMsg;//小缓存

    private AnalysisUtil(){};
    public static AnalysisUtil getInstance(){
        return instance;
    }

    public FileScaner getScaner() {
        return scaner;
    }

    /**
     * 初始化解析内容
     * @param lines
     */
    public void initScaner(List<String> lines) {
       scaner=new FileScaner();
       headMsg = null;
       scaner.setLineList(lines);
    }

    public String getLogPattern() {
        return logPattern;
    }

    public void setLogPattern(String logPattern) {
        this.logPattern = logPattern;
    }

    /**
     * 得到显示头信息
     */
    public ShowHeadMsg getHeadMsg() throws Exception {
        if(null==scaner||StringUtil.isEmpty(logPattern)){
            return null;
        }
        if(null!=headMsg){
           return headMsg;
        }

        synchronized (this) {
            if (null != headMsg) {
                return headMsg;
            }
            ShowHeadMsg headMsgTmp = new ShowHeadMsg();
            headMsgTmp.setLogPattern(logPattern);
            TomcatAccessLogValid.setHeadMsg(headMsgTmp);

            headMsgTmp.setRequestTotalCount(String.valueOf(scaner.getLineList().size()));

            if (-1 != headMsgTmp.getRequestStatusCountInt()) {
                //默认分析请求状态吗
                scaner.select(headMsgTmp.getRequestStatusCountInt() + ",count(" + headMsgTmp.getRequestStatusCountInt() + ")")
                        .groupBy(headMsgTmp.getRequestStatusCountInt() + "")
                        .orderBy(OrderBy.desc(1))
                        .list();
                List<List<Object>> httpCodeResult = scaner.getResult();//[[200,10],[500,20]]
                scaner.reset();

                Map<String, String> map = listToMap(httpCodeResult);
                int statusCount = 0;
                for (String str : map.values()) {
                    statusCount += (int) Double.valueOf(str).doubleValue();
                }
                map.put("total", String.valueOf(statusCount));
                map.forEach((k, v) -> {
                    if (!"total".equals(k)) {
                        headMsgTmp.getHttpStatusMap().add(new HashMap<String, String>() {{
                            put("statusCode", k);
                            put("statusCount", v);
                            put("statusProportion", NumberUtil.getPercent((int) Double.valueOf(v).doubleValue(), (int) Double.valueOf(map.get("total")).doubleValue()));
                        }});
                    }
                });

                // 根据Map中名为 "key" 的属性排序
                Collections.sort(headMsgTmp.getHttpStatusMap(), (map1, map2) -> {
                    Comparable value1 = (Comparable) map1.get("statusProportion");
                    Comparable value2 = (Comparable) map2.get("statusProportion");
                    return value2.compareTo(value1);
                });
//            headMsg.setRequest200Count(StringUtil.getStrFilterNull(map.get("200"), "-"));
//            headMsg.setRequest404Count(StringUtil.getStrFilterNull(map.get("404"), "-"));
//            headMsg.setRequest400Count(StringUtil.getStrFilterNull(map.get("400"), "-"));
//            headMsg.setRequest405Count(StringUtil.getStrFilterNull(map.get("405"), "-"));
//            headMsg.setRequest404Count(StringUtil.getStrFilterNull(map.get("500"), "-"));
            }

            if (-1 != headMsgTmp.getSingleRequestCountInt()) {
                //默认分析亲求IP数据
                scaner.select(headMsgTmp.getSingleRequestCountInt() + ",count(" + headMsgTmp.getSingleRequestCountInt() + ")")
                        .groupBy(headMsgTmp.getSingleRequestCountInt() + "")
                        .orderBy(OrderBy.desc(1))
                        .list();
                List<List<Object>> ipResult = scaner.getResult();//[[200,10],[500,20]]
                scaner.reset();

                headMsgTmp.setSingleRequestCount(StringUtil.getStrFilterNull(ipResult.size(), "-"));

                //单个IP访问次数
                Map<String, String> map = listToMap(ipResult);
                int ipCount = 0;
                for (String str : map.values()) {
                    ipCount += (int) Double.valueOf(str).doubleValue();
                }
                map.put("total", String.valueOf(ipCount));
                map.forEach((k, v) -> {
                    if (!"total".equals(k)) {
                        headMsgTmp.getIpRequestMap().add(new HashMap<String, String>() {{

                            put("ip", k);
                            put("ipCount", v);
                            put("addr", IPSearch.getIpInfo(k));
                            put("ipProportion", NumberUtil.getPercent((int) Double.valueOf(v).doubleValue(), (int) Double.valueOf(map.get("total")).doubleValue()));
                        }});
                    }
                });

                // 根据Map中名为 "key" 的属性排序
                Collections.sort(headMsgTmp.getIpRequestMap(), (map1, map2) -> {
                    Comparable value1 = (Comparable) map1.get("ipProportion");
                    Comparable value2 = (Comparable) map2.get("ipProportion");
                    return value2.compareTo(value1);
                });
            }

            if (-1 != headMsgTmp.getStaticFileCountInt()) {
                //静态文件数
                scaner.select(headMsgTmp.getStaticFileCountInt() + ",count(" + headMsgTmp.getStaticFileCountInt() + ")")
                        .where(Conditions.and(Conditions.regexMatch("5", ".*\\.(js|css|png).*$")))
                        .groupBy(headMsgTmp.getStaticFileCountInt() + "")
                        .orderBy(OrderBy.desc(1))
                        .list();
                List<List<Object>> staticFileResult = scaner.getResult();//[[200,10],[500,20]]
                scaner.reset();

                headMsgTmp.setStaticFileCount(StringUtil.getStrFilterNull(staticFileResult.size(), "-"));

                if (-1 == headMsgTmp.getAnalysisTimeInt()) {
                    //RUL分组
                    scaner.select(headMsgTmp.getStaticFileCountInt() + ",count(" + headMsgTmp.getStaticFileCountInt() + ")")
                            .processor(headMsgTmp.getStaticFileCountInt(), ProcessUtil.processor_url)
                            .groupBy(headMsgTmp.getStaticFileCountInt() + "")
                            .orderBy(OrderBy.desc(1))
                            .list();
                    List<List<Object>> urlFilterResult = scaner.getResult();//[[200,10],[500,20]]
                    scaner.reset();

                    //单个IP访问次数
                    Map<String, String> map = listToMap(urlFilterResult);
                    int urlFilterCount = 0;
                    for (String str : map.values()) {
                        urlFilterCount += (int) Double.valueOf(str).doubleValue();
                    }
                    map.put("total", String.valueOf(urlFilterCount));
                    map.forEach((k, v) -> {
                        if (!"total".equals(k)) {
                            headMsgTmp.getUrlFilterMap().add(new HashMap<String, String>() {{
                                put("urlFilter", k);
                                put("urlFilterCount", v);
                                put("urlFilterProportion", NumberUtil.getPercent((int) Double.valueOf(v).doubleValue(), (int) Double.valueOf(map.get("total")).doubleValue()));
                            }});
                        }
                    });

                    // 根据Map中名为 "key" 的属性排序
                    Collections.sort(headMsgTmp.getUrlFilterMap(), (map1, map2) -> {
                        Comparable value1 = (Comparable) map1.get("urlFilterProportion");
                        Comparable value2 = (Comparable) map2.get("urlFilterProportion");
                        return value2.compareTo(value1);
                    });
                } else {
                    //RUL分组
                    scaner.select(headMsgTmp.getStaticFileCountInt() + ",count(" + headMsgTmp.getStaticFileCountInt() + ")" + ",sum(" + headMsgTmp.getAnalysisTimeInt() + ")" + ",min(" + headMsgTmp.getAnalysisTimeInt() + ")" + ",max(" + headMsgTmp.getAnalysisTimeInt() + ")" + ",avg(" + headMsgTmp.getAnalysisTimeInt() + ")")
                            .processor(headMsgTmp.getStaticFileCountInt(), ProcessUtil.processor_url)
                            .groupBy(headMsgTmp.getStaticFileCountInt() + "")
                            .orderBy(OrderBy.desc(1))
                            .list();
                    List<List<Object>> urlFilterResult = scaner.getResult();//[[200,10],[500,20]]
                    scaner.reset();

                    int urlFilterCount = urlFilterResult.stream()
                            .mapToInt(list -> ((Double) list.get(1)).intValue())
                            .sum();

                    urlFilterResult.forEach(list -> {
                        headMsgTmp.getUrlFilterMap().add(new HashMap<String, String>() {{
                            put("urlFilter", String.valueOf(list.get(0)));
                            put("urlFilterCount", String.valueOf(list.get(1)));
                            put("urlFilterTotalTime", String.valueOf(list.get(2)));
                            put("urlFilterMinTime", String.valueOf(list.get(3)));
                            put("urlFilterMaxTime", String.valueOf(list.get(4)));
                            put("urlFilterAvgTime", String.valueOf(list.get(5)));
                            put("urlFilterProportion", NumberUtil.getPercent((int) Double.valueOf(String.valueOf(list.get(1))).doubleValue(), (int) Double.valueOf(urlFilterCount).doubleValue()));
                        }});
                    });

                    // 根据Map中名为 "key" 的属性排序
                    Collections.sort(headMsgTmp.getUrlFilterMap(), (map1, map2) -> {
                        Double value1 = Double.valueOf(map1.get("urlFilterCount"));
                        Double value2 = Double.valueOf(map2.get("urlFilterCount"));
                        return value2.compareTo(value1);
                    });
                }
            }
            headMsg=headMsgTmp;
            return headMsg;
        }
    }

    private Map<String, String> listToMap(List<List<Object>> list){
        try {
            // 使用Stream API转换为Map，遇到重复键时抛出异常
            Map<String, String> map = list.stream()
                    .collect(Collectors.toMap(
                            pair -> (String)pair.get(0),
                            pair -> String.valueOf(pair.get(1)),//java.lang.Double cannot be cast to java.lang.String
                            (existing, replacement) -> { throw new IllegalStateException("Duplicate key: " + existing); }
                    ));
           return map;
        } catch (IllegalStateException e) {
           log.error(e.getMessage(),e);
        }
        return new HashMap<>();
    }


    public Map<String,List> search(String patternSQL) throws Exception {
        scaner.reset();
        Map<String,List> resultMap=new HashMap<>();
        //String lql = "select 0,2,3 from 'localhost_access_log.2019-03-14.txt' limit 10";
        log.info("查询语句:"+patternSQL);
        LogQueryLanguageParserStateMachine qsr = new LogQueryLanguageParserStateMachine(patternSQL);
        qsr.start();
        List<List<Object>> result=qsr.getFileScaner(scaner).list();

        String selectStr=scaner.getSelectedPropsStr();
        List<Map<String,String>> headList=new ArrayList<>();
        for(String str:selectStr.split(",")){
            Map<String,String>temp=new HashMap<>();
            String selStr=str.trim();
            if( selStr.chars().allMatch(Character::isDigit)) {
                temp.put("field", headMsg.getLogPatternOld()[Integer.valueOf(selStr)]);
                temp.put("title", headMsg.getLogPatterns()[Integer.valueOf(selStr)]);
            }else{
                temp.put("field", selStr);
                if(selStr.startsWith("count")){
                    temp.put("title","总数");
                }else if(selStr.startsWith("sum")){
                    temp.put("title","求和");
                }else if(selStr.startsWith("max")){
                    temp.put("title","最大");
                }else if(selStr.startsWith("min")){
                    temp.put("title","最小");
                }else if(selStr.startsWith("avg")){
                    temp.put("title","平均数");
                }
            }
            headList.add(temp);
        }

        List<Map<String,String>> bodyList=new ArrayList<>();
        for(List<Object> obj : result){
            Map<String, String> temp = new HashMap<>();
            for(int i=0;i<obj.size();i++) {
                temp.put(headList.get(i).get("field"),String.valueOf(obj.get(i)));
            }
            bodyList.add(temp);
        }

        resultMap.put("head",headList);
        resultMap.put("body",bodyList);
        return resultMap;
    }
}
